<?php

class MsggItemValve extends CModel
{
    public $searchKey;
    public $pid;
    public $type;
    public $isoverclock;

    const DURATION_MINUTE = 'minute';
    const DURATION_HOUR = 'hour';
    const DURATION_DAY = 'day';

    const VERSION = 'v1.6';

    public static $fileSuffix = '.lock';
    public static $filePath = null;

    public static function getOptions($type)
    {

        $value = [];
        switch ($type) {
            case 'duration':
                $value['minute'] = self::DURATION_MINUTE;
                $value['hour'] = self::DURATION_HOUR;
                $value['day'] = self::DURATION_DAY;
                break;

        }
        return $value;

    }

    function __clone()
    {

    }

    public static function getLockFile($pre)
    {
        if (self::$filePath === null) {
            self::$filePath = Yii::app()->getRuntimePath() . DIRECTORY_SEPARATOR . 'lock';
        }
        if (!is_dir(self::$filePath)) {
            mkdir(self::$filePath, 0777, true);
        }
        $lockFile = '';
        if (!empty($pre)) {
            $lockFile = self::$filePath . DIRECTORY_SEPARATOR . md5($pre) . self::$fileSuffix;
        }
        return $lockFile;
    }

    public static function add($pre, $type, $time = null)
    {
        $time = empty($time) ? time() : $time;
        //lock
        $fp = fopen(self::getLockFile($pre), 'w');
        $minuteName = implode('_', [$pre, $type, self::DURATION_MINUTE, self::VERSION]);
        $hourName = implode('_', [$pre, $type, self::DURATION_HOUR, self::VERSION]);
        $dayName = implode('_', [$pre, $type, self::DURATION_DAY, self::VERSION]);
        if (empty($pre)) {
            return;
        }
        if (flock($fp, LOCK_EX)) {
            Yii::log($pre . '获取锁', CLogger::LEVEL_WARNING, __METHOD__);
            if (($cache = Yii::app()->cache)) {
                if (!$cacheValue = $cache->get($minuteName)) {
                    $cacheValue = ['ts' => $time, 'data' => [], 'total' => 0];
                } else {
                    $cacheValue = json_decode($cacheValue, true);
                }
                $ts = isset($cacheValue['ts']) ? $cacheValue['ts'] : $time;
                $data = isset($cacheValue['data']) ? $cacheValue['data'] : [];
                $total = isset($cacheValue['total']) ? $cacheValue['total'] : 0;
                if ($time - $ts <= 60 && $time - $ts >= 0) {
                    if (!isset($data[$time])) {
                        $data[$time] = 0;
                    }
                    $data[$time] += 1;
                    $total += 1;
                } elseif ($time - $ts > 60) {
                    foreach ($data as $key => $value) {
                        if ($key <= $time - 60) {
                            $total -= $data[$key];
                            unset($data[$key]);
                        }
                    }
                    if (isset($data[$time])) {
                        $data[$time] += 1;
                    } else {
                        $data[$time] = 1;
                    }
                    $total += 1;
                }
                $ts = $time - 60;

                $cacheValue['data'] = $data;
                $cacheValue['ts'] = $ts;
                $cacheValue['total'] = $total < 0 ? 0 : $total;
                $cache->set($minuteName, json_encode($cacheValue), 60);
                //per hour
                if (!$cacheValue = $cache->get($hourName)) {
                    $cacheValue = ['ts' => $time, 'data' => [], 'total' => 0];
                } else {
                    $cacheValue = json_decode($cacheValue, true);
                }

                $ts = isset($cacheValue['ts']) ? $cacheValue['ts'] : $time;
                $data = isset($cacheValue['data']) ? $cacheValue['data'] : [];
                $total = isset($cacheValue['total']) ? $cacheValue['total'] : 0;
                $minute = intval($time / 60);
                if (!isset($data[$minute])) {
                    $data[$minute] = 0;
                }
                if ($time - $ts <= 3600 && $time - $ts >= 0) {
                    $data[$minute] += 1;
                    $total += 1;
                } elseif ($time - $ts > 3600) {
                    foreach ($data as $key => $value) {
                        if ($key <= intval(($time - 3600) / 60)) {
                            $total -= $data[$key];
                            unset($data[$key]);
                        }
                    }
                    if (isset($data[$minute])) {
                        $data[$minute] += 1;
                    } else {
                        $data[$minute] = 1;
                    }
                    $total += 1;
                }

                $ts = $time - 3600;

                $cacheValue['data'] = $data;
                $cacheValue['ts'] = $ts;
                $cacheValue['total'] = $total < 0 ? 0 : $total;
                $cache->set($hourName, json_encode($cacheValue), 3600);
                //per day
                if (!$cacheValue = $cache->get($dayName)) {
                    $cacheValue = [
                        'ts' => $time,
                        'data' => [],
                        'total' => 0
                    ];
                } else {
                    $cacheValue = json_decode($cacheValue, true);
                }
                $ts = isset($cacheValue['ts']) ? $cacheValue['ts'] : $time;
                $data = isset($cacheValue['data']) ? $cacheValue['data'] : [];
                $total = isset($cacheValue['total']) ? $cacheValue['total'] : 0;
                $hour = intval($time / 3600);
                if (!isset($data[$hour])) {
                    $data[$hour] = 0;
                }
                if ($time - $ts <= 24 * 3600 && $time - $ts >= 0) {
                    $data[$hour] += 1;
                    $total += 1;
                } elseif ($time - $ts > 24 * 3600) {
                    foreach ($data as $key => $value) {
                        if ($key <= intval(($time - 24 * 3600) / 3600)) {
                            $total -= $data[$key];
                            unset($data[$key]);
                        }
                    }
                    if (isset($data[$hour])) {
                        $data[$hour] += 1;
                    } else {
                        $data[$hour] = 1;
                    }
                    $total += 1;
                }
                $ts = $time - 24 * 3600;
                $cacheValue['data'] = $data;
                $cacheValue['ts'] = $ts;
                $cacheValue['total'] = $total < 0 ? 0 : $total;
                $cache->set($dayName, json_encode($cacheValue), 24 * 3600);
            }
            flock($fp, LOCK_UN);
        } else {
            Yii::log($pre . '锁失败', CLogger::LEVEL_ERROR, __METHOD__);
        }
        fclose($fp);
    }

    public static function isOverClock($pre, $type, array $limit = [], $time = null)
    {
        if (empty($pre)) {
            return false;
        }
        $time = empty($time) ? time() : $time;
        $fp = fopen(self::getLockFile($pre), 'w');
        if (flock($fp, LOCK_EX)) {
            Yii::log($pre . '获取锁', CLogger::LEVEL_WARNING, __METHOD__);
            $data = self::getTotals($pre, $type, $time);
            flock($fp, LOCK_UN);
        } else {
            Yii::log($pre . '锁失败', CLogger::LEVEL_ERROR, __METHOD__);
        }
        fclose($fp);
        Yii::log($pre . '' . json_encode($data), CLogger::LEVEL_WARNING, __METHOD__);
        $isOverClock = false;
        foreach ($limit as $duration => $l) {
            if (isset($data[$duration]) && $l !== null && $data[$duration] >= $l) {
                $isOverClock = true;
                break;
            }
        }
        return $isOverClock;
    }

    //for get  residue in hour minute day
    public static function getResidue($pre, $type, array $limit = [], $time = null)
    {
        //default
        $residue = 0;
        $time = empty($time) ? time() : $time;
        if (!self::isOverClock($pre, $type, $limit, $time)) {
            $nowDatas = self::getTotals($pre, $type, $time);
            $arrayResidue = [];
            foreach ($nowDatas as $duration => $data) {
                if (isset($limit[$duration])) {
                    $arrayResidue[$duration] = ($limit[$duration] - $data) <= 0 ? 0 : ($limit[$duration] - $data);
                }
            }
            if (!empty($arrayResidue)) {
                ksort($arrayResidue);
                $residue = end($arrayResidue);
            }
        }
        return $residue <= 0 ? 0 : $residue;
    }

    public static function getTotalsByDuration($pre, $type, $duration, $time = null)
    {
        $totals = self::getTotals($pre, $type, $time);
        return isset($totals[$duration]) ? $totals[$duration] : 0;
    }

    //get the last data in cache by name
    public static function getTotals($pre, $type, $time = null)
    {
        if (empty($pre)) {
            return 0;
        }
        $time = empty($time) ? time() : $time;
        $totals = [self::DURATION_HOUR => 0, self::DURATION_MINUTE => 0, self::DURATION_DAY => 0];
        if (($cache = Yii::app()->cache)) {
            $minuteName = implode('_', [$pre, $type, self::DURATION_MINUTE, self::VERSION]);
            $hourName = implode('_', [$pre, $type, self::DURATION_HOUR, self::VERSION]);
            $dayName = implode('_', [$pre, $type, self::DURATION_DAY, self::VERSION]);
            $minuteValue = json_decode($cache->get($minuteName, json_encode(['ts' => time(), 'total' => 0, 'data' => []])), true);
            if (!empty($minuteValue)) {
                $ts = $minuteValue['ts'];
                $total = $minuteValue['total'];
                if ($time - $ts > 60) {
                    $data = $minuteValue['data'];
                    foreach ($data as $key => $value) {
                        if ($key <= $time - 60) {
                            if (isset($data[$key])) {
                                $total -= $data[$key];
                            }
                        }
                    }
                }
                $totals['minute'] = $total;
            }
            $hourValue = json_decode($cache->get($hourName, json_encode(['ts' => time(), 'total' => 0, 'data' => []])), true);
            if (!empty($hourValue)) {
                $ts = $hourValue['ts'];
                $total = $hourValue['total'];
                if ($time - $ts > 3600) {
                    $data = $hourValue['data'];
                    foreach ($data as $key => $value) {
                        if ($key <= intval(($time - 3600) / 60)) {
                            if (isset($data[$key])) {
                                $total -= $data[$key];
                            }
                        }
                    }
                }
                $totals['hour'] = $total;
            }

            $dayValue = json_decode($cache->get($dayName, json_encode(['ts' => time(), 'total' => 0, 'data' => []])), true);
            if (!empty($dayValue)) {
                $ts = $dayValue['ts'];
                $total = $dayValue['total'];
                if ($time - $ts > 3600 * 24) {
                    $data = $dayValue['data'];
                    foreach ($data as $key => $value) {
                        if ($key <= intval(($time - 3600 * 24) / 3600)) {
                            if (isset($data[$key])) {
                                $total -= $data[$key];
                            }
                        }
                    }
                }
                $totals['day'] = $total;
            }

        }
        return $totals;
    }

    public static function getPres(AlarmPerson $person, $types = null)
    {
        if ($types == null) {
            $types = array_keys(MsggItem::getOptions('type'));
        }
        if (!is_array($types)) {
            $types = [$types];
        }
        $pres = array();
        foreach ($types as $type) {
            switch ($type) {
                case MsggItem::TYPE_CALL:
                case MsggItem::TYPE_SMS:
                    $pres[$type] = $person->phone;
                    break;
                case MsggItem::TYPE_WECHAT:
                    $pres[$type] = $person->wechat;
                    break;
                case MsggItem::TYPE_MAIL:
                    $pres[$type] = $person->mail;
                    break;
            }
        }
        return $pres;
    }

    public function getDataProvider()
    {
        $persons = AlarmPerson::getOptions('person');
        $types = array_keys(MsggItem::getOptions('type'));
        if (isset($this->pid) && $this->pid != '') {
            $persons = [$persons[$this->pid]];
        }
        if (isset($this->type) && !empty($this->type)) {
            $types = [$this->type];
        }

        $data = array();

        foreach ($persons as $person) {

            $pid = $person->id;
            $cnname = $person->cnname;

            $rowData = ['pid' => $pid, 'cnname' => $cnname];
            foreach ($types as $type) {
                $rowData['type'] = $type;
                $limit = MsggItem::getLimit($type);
                $pre = '';
                switch ($type) {
                    case MsggItem::TYPE_SMS:
                    case MsggItem::TYPE_CALL:
                        $pre = $person->phone;
                        break;
                    case MsggItem::TYPE_WECHAT:
                        $pre = $person->wechat;
                        break;
                    case MsggItem::TYPE_MAIL:
                        $pre = $person->mail;
                        break;
                }
                $isoverClock = self::isOverClock($pre, $type, $limit);
                if (isset($this->isoverclock) && $this->isoverclock != '' && $isoverClock != ($this->isoverclock == 'false' ? false : true)) {
                    continue;
                }
                $total = self::getTotals($pre, $type);
                $rowData['limit'] = json_encode($limit);
                $rowData['isoverclock'] = $isoverClock;
                $rowData['total'] = json_encode($total);
                $rowData['pre'] = $pre;
                $data[] = $rowData;
            }

        }
        return new CArrayDataProvider($data, array(
            'pagination' => array(
                'pageSize' => 10,
            ),
        ));
    }

    public function attributeLabels()
    {
        return array(
            'pid' => 'pid',
            'type' => 'type',
            'isoverclock' => 'isoverclock'
        );
    }


    public function attributeNames()
    {
        // TODO: Implement attributeNames() method.
        return array(
            'pid' => 'pid',
            'type' => 'type',
            'isoverclock' => 'isoverclock',
        );
    }

    public function rules()
    {
        return array(
            array('pid, type ,isoverclock', 'safe'),
        );

    }

    public static function clean($pre, $type)
    {
        //lock
        $fp = fopen(self::getLockFile($pre), 'w');
        $minuteName = implode('_', [$pre, $type, self::DURATION_MINUTE, self::VERSION]);
        $hourName = implode('_', [$pre, $type, self::DURATION_HOUR, self::VERSION]);
        $dayName = implode('_', [$pre, $type, self::DURATION_DAY, self::VERSION]);
        if (empty($pre)) {
            return false;
        }
        if (flock($fp, LOCK_EX)) {
            Yii::log($pre . '获取锁', CLogger::LEVEL_WARNING, 'MsggItemValve.clean');
            if (($cache = Yii::app()->cache)) {
                $cache->set($minuteName, null);
                //per hour
                $cache->set($hourName, null);
                //per day
                $cache->set($dayName, null);
            }
            flock($fp, LOCK_UN);
        } else {
            Yii::log($pre . '锁失败', CLogger::LEVEL_ERROR, 'MsggItemValve.clean');
            return false;

        }
        fclose($fp);
        return true;
    }


}